﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using l1cs.server.serverpackets;

namespace l1cs.server
{
    class LoginController
    {
        private static LoginController _instance;

        private static Logger _log = Logger.getLogger( typeof( LoginController ).FullName );

        /// <summary>アカウント名(String)をキーとしたClientThreadのハッシュ。</summary>
        private Hashtable _accounts = Hashtable.Synchronized( new Hashtable() );

        private int _maxAllowedOnlinePlayers;

        private LoginController() { }

        public static LoginController getInstance()
        {
            if ( _instance == null )
            {
                _instance = new LoginController();
            }
            return _instance;
        }

        /// <summary>
        /// 接続先IPアドレスで既に接続があるか？
        /// </summary>
        /// <param name="ip">接続先IPアドレス</param>
        /// <returns>接続がある場合はTrue</returns>
        public bool isAlready( string ip )
        {
            lock ( _accounts )
            {
                foreach ( ClientThread tempClient in _accounts.Values )
                {
                    if ( ip.Equals( tempClient.getIp() ) )
                    {
                        return true;
                    }
                }
                return false;
            }
        }
        public int getOnlinePlayerCount()
        {
            return _accounts.Count;
        }

        public int getMaxAllowedOnlinePlayers()
        {
            return _maxAllowedOnlinePlayers;
        }

        public void setMaxAllowedOnlinePlayers( int maxAllowedOnlinePlayers )
        {
            _maxAllowedOnlinePlayers = maxAllowedOnlinePlayers;
        }

        private void kickClient( ClientThread client )
        {
            if ( client == null )
            {
                return;
            }
            ThreadPool.QueueUserWorkItem( new WaitCallback( client.threadSub ), client );
        }

        private void kickClientThreadSub( object state )
        {
            //GeneralThreadPool.getInstance().execute(new Runnable() {
            //    @Override
            //    public void run() {
            ClientThread client = (ClientThread)state;
            if ( client.getActiveChar() != null )
            {
                client.getActiveChar().sendPackets( new S_ServerMessage( 357 ) );
            }

            Thread.Sleep( 1000 );
            client.kick();
            //    }
            //});
        }

        public const int LOGIN_OK = 0;
        public const int ACCOUNT_IS_VALID = 1;
        public const int GAME_SERVER_FULL = 2;
        public const int ACCOUNT_ALREADY_LOGIN = 3;

        public int login( ClientThread client, Account account )
        {
            lock ( this )
            {
                if ( !account.isValid() )
                {
                    // パスワード認証がされていない、あるいは認証に失敗したアカウントが指定された。
                    // このコードは、バグ検出の為にのみ存在する。
                    return ACCOUNT_IS_VALID;
                }
                if ( ( getMaxAllowedOnlinePlayers() <= getOnlinePlayerCount() ) && !account.isGameMaster() )
                {
                    // ログイン数MAX
                    return GAME_SERVER_FULL;
                }
                if ( _accounts.ContainsKey( account.getName() ) )
                {
                    // 重複ログイン
                    ClientThread kickcl = (ClientThread)_accounts[account.getName()];
                    _accounts.Remove( account.getName() );
                    kickClient( kickcl );
                    return ACCOUNT_ALREADY_LOGIN;
                }
                _accounts[account.getName()] = client;
                return LOGIN_OK;
            }
        }

        public void logout( ClientThread client )
        {
            if ( client.getAccountName() != null )
            {

                _accounts.Remove( client.getAccountName() );
            }
        }
    }
}
